#![allow(dead_code)]
use redius::client::RedisClient;
use std::{future::Future, time::Duration};

fn main() {
    init_logger();
    build_async_runtime(run_internal());
}

async fn run_internal() {
    let builder = redius::RedisClientBuilder::new_standalone("192.168.128.131", 6379)
        .password("111111").reconnect_interval(Duration::from_secs(3));
    match  builder.build_and_connect().await {
        Ok(client) => {
            // string_set(&client).await;
            // string_get(&client).await;
            // string_append(&client).await;
            // string_get_del(&client).await;
            // string_get_ex(&client).await;
            // string_mget(&client).await;
            // string_set_range(&client).await;
            string_substr(&client).await;
        }
        Err(err) => {
            log::error!("{:?}", err);
        }
    }
    match tokio::signal::ctrl_c().await {
        Ok(_) => {
            log::info!("exit, bye bye ~");
        }
        Err(err) => {
            log::error!("{}", err);
        }
    }
}

async fn string_set(client: &RedisClient) {
    match client.string_get("abc").await {
        Ok(str) => {
            log::info!("get {str:?}");
        }
        Err(err) => {
            log::error!("error on string get, {err}");
        }
    }
}

async fn string_get(client: &RedisClient) {
    match client.string_get("hello").await {
        Ok(Some(str)) => {
            log::info!("hello = {str}");
        }
        Ok(None) => {
            log::info!("hello = null");
        }
        Err(err) => {
            log::error!("error on string set, {err}");
        }
    }
}

async fn string_append(client: &RedisClient) {
    match client.string_append("key123", "abcabc").await {
        Ok(num) => {
            log::info!("append num = {num}");
        }
        Err(err) => {
            log::error!("error on string append, {err}");
        }
    }
}

async fn string_get_del(client: &RedisClient) {
    match client.string_get_del("abcd").await {
        Ok(Some(str)) => {
            log::info!("abcd = {str}");
        }
        Ok(None) => {
            log::info!("abcd = null");
        }
        Err(err) => {
            log::error!("error on string get_del, {err}");
        }
    }
}

async fn string_get_ex(client: &RedisClient) {
    match client.string_get_ex("abcd", None).await {
        Ok(Some(str)) => {
            log::info!("abcd = {str}");
        }
        Ok(None) => {
            log::info!("abcd = null");
        }
        Err(err) => {
            log::error!("error on string get_del, {err}");
        }
    }
}

async fn string_mget(client: &RedisClient) {
    match client.string_mget(&["abcd2", "abcd", "abcd1"]).await {
        Ok(result) => {
            for item in result.iter() {
                match item {
                    Some(val) => {
                        log::info!("{val}");
                    }
                    None => {
                        log::info!("null");
                    }
                }
            }
        }
        Err(err) => {
            log::error!("error on string get_del, {err}");
        }
    }
}

async fn string_set_range(client: &RedisClient) {
    match client.string_set_range("abcd111", 2, "hello").await {
        Ok(result) => {
            log::info!("len = {result}");
        }
        Err(err) => {
            log::error!("error on string get_del, {err}");
        }
    }
}

async fn string_substr(client: &RedisClient) {
    match client.string_substr("abcd", 2, 2).await {
        Ok(str) => {
            log::info!("abcd = {str}");
        }
        Err(err) => {
            log::error!("error on string substr, {err}");
        }
    }
}

static TEST_LOGGER: TestLogger = TestLogger::new();

fn init_logger() {
    _ = log::set_logger(&TEST_LOGGER);
    log::set_max_level(log::LevelFilter::Trace);
}

fn build_async_runtime(action: impl Future) {
    tokio::runtime::Builder::new_multi_thread()
        .worker_threads(3)
        .enable_all()
        .build()
        .unwrap()
        .block_on(action);
}

pub struct TestLogger {}

impl TestLogger {
    const fn new() -> Self {
        Self {}
    }
}

impl log::Log for TestLogger {
    fn enabled(&self, _: &log::Metadata) -> bool {
        return true;
    }

    fn log(&self, record: &log::Record) {
        let level = record.level();
        let cur = chrono::Local::now().format("%Y-%m-%d %H:%M:%S.%3f");
        if level <= log::Level::Error {
            println!(
                "{cur} {level} file = {}, mod = {}, line = {}, {}",
                record.file().unwrap_or("unknow"),
                record.target(),
                record.line().unwrap_or(0),
                record.args().to_string()
            );
        } else {
            println!("{cur} {level} {}", record.args().to_string());
        }
    }

    fn flush(&self) {}
}
